#include <string.h>

#include "lib.h"
#include "stream.h"
#include "pkg.h"
#include "mfestprv.h"

bool8 
PMHead::load(pCStream File)
{
	//
	// NOTE:  MUST always allow for older versions!
	//
	if (sizeof(PMHead) != CStreamRead(File, &ID, sizeof(PMHead)))
		goto abort;

	if (ID != PMH_Id || Version < 0x00010000L)
		goto abort;

	if (sizeof(PMHead) != Size &&
		streamEOF == CStreamSeek(File,
			(int32)Size - (int32)sizeof(PMHead), streamSEEK_CUR))
		goto abort;

	//
	// future versions read extra data here
	//

	return true;

abort:
	return false;
}

bool8 
PMHead::save(pCStream File, uint32 NumPkgs, uint32 NumFilenames)
{
	this->NumPkgs = NumPkgs;
	this->NumFilenames = NumFilenames;
	FilenameOfs = 0;			// filled in later (if used)

	ID = PMH_Id;
	Version = PMH_Version;
	Size = sizeof(PMHead);
	SizePkg = sizeof(PMPackage);
	SizeGame = 0;

	if (sizeof(PMHead) != CStreamWrite(File, &ID, sizeof(PMHead)))
		goto abort;

	return true;

abort:
	return false;
}

bool8 
PMHeadV12::save(pCStream File, uint32 NumPkgs, uint32 NumFilenames)
{
	this->NumPkgs = NumPkgs;
	this->NumFilenames = NumFilenames;
	FilenameOfs = 0;			// filled in later (if used)

	ID = PMH_Id;
	Version = PMH_Version;
	Size = sizeof(PMHead);
	SizePkg = sizeof(PMPackage);
	SizeGame = 0;

	if (sizeof(PMHead) != CStreamWrite(File, &ID, sizeof(PMHead)))
		goto abort;

	return true;

abort:
	return false;
}


bool8
PMHead::saveFileOfs(pCStream File)
{
	uint32 ofs = (uint32)CStreamTell(File);

	return (bool8)(ofs != (uint32)streamEOF &&
		streamEOF != CStreamSeek(File,
			(char*)&FilenameOfs - (char*)&ID, streamSEEK_SET) &&
		sizeof(uint32) == CStreamWrite(File, &ofs, sizeof(uint32)) &&
		streamEOF != CStreamSeek(File, ofs, streamSEEK_SET));
}

bool8
PMHeadV12::saveFileOfs(pCStream File)
{
	uint32 ofs = (uint32)CStreamTell(File);

	return (bool8)(ofs != (uint32)streamEOF &&
		streamEOF != CStreamSeek(File,
			(char*)&FilenameOfs - (char*)&ID, streamSEEK_SET) &&
		sizeof(uint32) == CStreamWrite(File, &ofs, sizeof(uint32)) &&
		streamEOF != CStreamSeek(File, ofs, streamSEEK_SET));
}


bool8
PMPackage::load(pCStream File, const PMHead& PMH, Package* Pkg)
{
	char buf[256];

	//defult unzip size
	UnZipSize = 0;

	//
	// NOTE:  MUST always allow for older versions!
	//
	if (PMH.Version <= 0x00010002L)
	{
		PMPackageV12 oldp;

		if (PMH.SizePkg != (uint32)CStreamRead(File, &oldp, PMH.SizePkg))
			goto abort;

		NameLen = oldp.NameLen;
		DLLNameLen = oldp.DLLNameLen;
		ZipSize = oldp.ZipSize;
		Version = oldp.Version;
		Flags = oldp.Flags;		//note: PMPackage uses the same flags for both versions!

		if (NameLen &&
			NameLen != (uint32)CStreamRead(File, buf, NameLen))
			goto abort;
		buf[NameLen] = '\0';
		Pkg->setName(buf);
		
		if (DLLNameLen &&
			DLLNameLen != (uint32)CStreamRead(File, buf, DLLNameLen))
			goto abort;
		buf[DLLNameLen] = '\0';
		Pkg->setDLLName(buf);

		if (!Pkg->isLobby())
		{
			PkgDependency	PkgDp("Lobby", oldp.ReqLobbyVer);;
			Pkg->addDependency(&PkgDp);
		}

		for(int32 i=0;i<oldp.NumGames;i++)
		{
			PMGame unusedGames;

			//read the game data and ignore it
			if (PMH.SizeGame != (uint32)CStreamRead(File, &unusedGames, PMH.SizeGame))
				goto abort;

			if (unusedGames.NameLen &&
				unusedGames.NameLen != (uint32)CStreamRead(File, buf, unusedGames.NameLen))
				goto abort;

			if (unusedGames.IconNameLen &&
				unusedGames.IconNameLen != (uint32)CStreamRead(File, buf, unusedGames.IconNameLen))
				goto abort;
		}
	}
	else
	{
		if (PMH.SizePkg != (uint32)CStreamRead(File, &NameLen, PMH.SizePkg))
			goto abort;

		if (NameLen &&
			NameLen != (uint32)CStreamRead(File, buf, NameLen))
			goto abort;
		buf[NameLen] = '\0';
		Pkg->setName(buf);
		
		if (DLLNameLen &&
			DLLNameLen != (uint32)CStreamRead(File, buf, DLLNameLen))
			goto abort;
		buf[DLLNameLen] = '\0';
		Pkg->setDLLName(buf);

		//special case.. if there is no dll name then it can't be installed!
		//how can a game be installed if it doesn't know what dll to load!
		if (DLLNameLen == 0)
			Flags &= ~INSTALLED;

		Pkg->clearDepends();

		for(uint8 i=0;i<NumDepends;i++)
		{
			PMDependency		pmd;
			PkgDependency		PkgDp;
	
			if (pmd.load(File, PMH, &PkgDp))
			{
				Pkg->addDependency(&PkgDp);
			}
			else
				goto abort;
		}
	}

	Pkg->setLocalVersion(Version);
	Pkg->setServerVersion(0);
	Pkg->setZipSize(ZipSize);
	Pkg->setUnZipSize(UnZipSize);

//	if (Flags & LOBBY)
//		Pkg->setLobby(true);
	
	if (Flags & INSTALLED)
		Pkg->setInstalled(true);
	else 
		Pkg->setInstalled(false);

	return true;

abort:
	return false;
}

bool8
PMPackage::save(pCStream File, Package* p)
{
	char buffer[255];
	uint8 i;
	PkgDependency* dependency = 0;

	// load up the structure
	//
	StringConversions::convert(buffer, p->getName(), 255);
	NameLen = strlen(buffer);

	StringConversions::convert(buffer, p->getDLLName(), 255);
	DLLNameLen = strlen(buffer);

	ZipSize = p->getZipSize();
	Version = p->getLocalVersion();
	NumDepends = p->getNumDependency();
	UnZipSize = p->getUnZipSize();

	Flags = NONE;
//	if (p->isLobby())
//		Flags |= LOBBY;
	if (p->isInstalled())
		Flags |= INSTALLED;
	
	// save it all
	//
	if (sizeof(PMPackage) != CStreamWrite(File, &NameLen, sizeof(PMPackage)))
		goto abort;

	StringConversions::convert(buffer, p->getName(), 255);
	if (NameLen &&
		NameLen != CStreamWrite(File, buffer, NameLen))
		goto abort;

	StringConversions::convert(buffer, p->getDLLName(), 255);
	if (DLLNameLen &&
		DLLNameLen != CStreamWrite(File, buffer, DLLNameLen))
		goto abort;

	dependency = p->getDependencies();
	for(i=0;i<NumDepends;i++)
	{
		PMDependency pmd;
		
		if (!pmd.save(File, &dependency[i]))
			goto abort;
	}

	return true;
abort:
	return false;
}

bool8
PMPackageV12::save(pCStream File, Package* p)
{
	char buffer[255];
	
	// load up the structure
	//
	StringConversions::convert(buffer, p->getName(), 255);
	NameLen = strlen(buffer);

	StringConversions::convert(buffer, p->getDLLName(), 255);
	DLLNameLen = strlen(buffer);

	NumGames = 0;
	ZipSize = p->getZipSize();
	Version = p->getLocalVersion();
	ReqLobbyVer = p->getDependencyVersion(TEXT("Lobby"));

	Flags = NONE;
	if (p->isLobby())
		Flags |= LOBBY;
	if (p->isInstalled())
		Flags |= INSTALLED;

	// save it all
	//
	if (sizeof(PMPackage) != CStreamWrite(File, &NameLen, sizeof(PMPackage)))
		goto abort;

	StringConversions::convert(buffer, p->getName(), 255);
	if (NameLen &&
		NameLen != CStreamWrite(File, buffer, NameLen))
		goto abort;

	StringConversions::convert(buffer, p->getDLLName(), 255);
	if (DLLNameLen &&
		DLLNameLen != CStreamWrite(File, buffer, DLLNameLen))
		goto abort;

	return true;
abort:
	return false;
}

bool8
PMDependency::load(pCStream File,const PMHead& PMH, PkgDependency *PkgD)
{
	char name[256];

	if (sizeof(PMDependency) != CStreamRead(File, &DependencyNameLen, sizeof(PMDependency)))
		goto abort;

	if (DependencyNameLen &&
		DependencyNameLen != (uint32)CStreamRead(File, name, DependencyNameLen))
		goto abort;
	name[DependencyNameLen] = '\0';

	PkgD->setName(name);
	PkgD->setRequiredVersion(RequiredVersion);

	return true;

abort:
	return false;
}


bool8
PMDependency::save(pCStream File, PkgDependency* p)
{
	char buffer[255];

	// load up the structure
	//
	StringConversions::convert(buffer, p->getName(), 255);
	DependencyNameLen = strlen(buffer);

	RequiredVersion = p->getRequiredVersion();

	// save it all
	//
	if (sizeof(PMDependency) != CStreamWrite(File, &DependencyNameLen, sizeof(PMDependency)))
		goto abort;

	if (DependencyNameLen &&
		DependencyNameLen != CStreamWrite(File, buffer, DependencyNameLen))
		goto abort;

	return true;
abort:
	return false;
}
